

#include "stout.h"

#include <ctype.h>

namespace stout
{
	std::istream &operator >> (std::istream &_in, stout::lexer &_lex)
	{
		std::string str;

		while (_in >> str)
		{
			_lex.push_back (str);

			std::cout << str << _lex.back ().Lexeme << std::endl;
		}

		return _in;
	}
	
	
	std::istream &operator >> (std::istream &_in, stout::parser &_par)
	{
		try
		{
			_in >> _par.Lexer;
		}
		catch (std::string &_err)
		{
			throw std::string ("lexer: ") + _err;
		}

		_par.block ();

		if (_par.Lexer.size () > 1)
		{
			throw std::string ("block ended before input stream.");
		}

		return _in;
	}
};


stout::token::token (const std::string &_src) : Source (_src)
{
	if (_src.empty ())
	{
		throw std::string ("empty token");
	}

	if (isdigit (_src [0]))
	{
		Lexeme = NUM;
	}
	else if (_src == "var")
	{
		Lexeme = VAR;
	}
	else if (_src == "try")
	{
		Lexeme = TRY;
	}
	else if (_src == "while")
	{
		Lexeme = WHILE;
	}
	else if (isalpha (_src [0]) || _src [0] == '_')
	{
		Lexeme = ID;
	}
	else switch (_src [0])
	{
	case '=' : 
		Lexeme = EQUALS;
		break;
	case '+' : 
		Lexeme = PLUS;
		break;
	case '{' :
		Lexeme = LCURL;
		break;
	case '}' :
		Lexeme = RCURL;
		break;
	case '(' :
		Lexeme = LPAREN;
		break;
	case ')' :
		Lexeme = LPAREN;
		break;

	default:
		throw std::string ("unknown token ") + _src;
	}

}


void stout::parser::block ()
{
	if (Lexer.front ().Lexeme != LCURL)
	{
		throw std::string ("expected `{' to begin block");
	}

	push <closure> ();

	do
	{
		Lexer.next ();
	} while (stmnt ());

	if (Lexer.front ().Lexeme != RCURL)
	{
		throw std::string ("expected `}' to end block");
	}

	pop ();
}


bool stout::parser::stmnt ()
{
	switch (Lexer.front ().Lexeme)
	{
	case VAR :
		Lexer.next ();
		if (Lexer.front ().Lexeme != ID)
		{
			throw std::string ("expected identifier following `var' statement");
		}
		define ();		// define the current token as an identifier
		push <assignment> ();	// for assigning to new identifier
		Lexer.next ();
		if (Lexer.front ().Lexeme != EQUALS)
		{
			throw std::string ("expected initializer follwing `var' statement");
		}	
		Lexer.next ();
		expr ();
		pop ();

		break;
	case ID :
		lhand ();
		break;

	case TRY :
//		push <tryblock> ();
		Lexer.next ();
		block ();
//		pop ();
		break;

	case WHILE :
//		push <whileblock> ();
		expr ();
		block ();
//		pop ();
		break;

	case LCURL :
		block ();
		break;

	case RCURL :
		return false;

	default :
		throw std::string ("expected statement or end of block");
	};

	return true;
}


void stout::parser::expr ()
{
	switch (Lexer.front ().Lexeme)
	{
	case ID :
	case NUM :
		term ();
		break;

	case LPAREN :
		expr ();
		Lexer.next ();

		if (Lexer.front ().Lexeme != RPAREN)
		{
			throw std::string ("expected matching ')'");
		}

		break;
	}
}


void stout::parser::term ()
{
	switch (Lexer.front ().Lexeme)
	{
	case PLUS :
	case MINUS :
		expr ();
	}
}


void stout::parser::lhand ()
{
	Lexer.next ();
}

